/**
* @brief    开关设备驱动
* @file     XxxSwitchScan_Driver.c
* @author   何锡斌
* @email    2537274979@qq.com
* @date     2024/01/19
* @version  V1_0_0
* @par      实现功能：
* - 支持多开关设备(按键等)的短按/短按抬起/长按/持续长按/长按抬起/连击/单边沿触发 事件响应；
* - 支持每个设备的按下消抖与抬起消抖的独立配置；
* - 支持每个设备的每个事件响应的独立开启与关闭；
* @par      注意事项：
* - 首次触发的连击事件即为双击，此时`XxxSwitchDevice_ReadComboHitNum()`函数读取到的连击次数返回即为2；
* - 连击一旦没续上则连击次数会被清零，所以在触发连击事件时按需求是否利用或保存连击次数；
* - 边沿模式仅能单边沿触发；
* - 在操作系统中使用时，如果其中一个设备使用到的IPC是阻塞方式，会导致其他设备的扫描被阻塞；
* - tick是由调用者外部决定的，以1~20ms为一次tick均可。tick越小，功耗与cpu占用越高；
* - 消抖时长(计数数值*tick)，一般为10~50ms，由实际抖动程度决定；
* @par      修改日志：
* <table>
* <tr><th>日期          <th>版本        <th>作者    <th>更新内容        </tr>
* <tr><td>2024/01/19    <td>V1_0_0      <td>何锡斌  <td>初版发布；      </tr>
* </table>
*/
#include "./XxxSwitchScan/XxxSwitchScan_Driver.h"



#ifndef NULL
	#define NULL	(void*)0
#endif



/**开关检测步骤*/
typedef enum{
	SwitchCheckStep_Wait2Trigger = 0,					/**< 等待触发 */
	SwitchCheckStep_Wait,								/**< 消抖 */
	SwitchCheckStep_Wait2Long,							/**< 等待长按 */
	SwitchCheckStep_Wait2Continue,						/**< 等待持续长按 */
	SwitchCheckStep_Wait2Up,							/**< 等待抬起 */
	#if CFG_XXXSWITCH_COMBOHIT
	SwitchCheckStep_Wait2ComboHit,						/**< 等待连击 */
	SwitchCheckStep_ComboHitWait,						/**< 连击消抖 */
	SwitchCheckStep_Wait2ComboHitUp,					/**< 等待连击抬起 */
	#endif
	#if (CFG_XXXSWITCH_COMBOHIT || CFG_XXXSWITCH_EDGETRIGGER)
	SwitchCheckStep_WaitNotTrigge,						/**< 等待复位 */
	#endif
}enum_XxxSwitchCheckStep;


/**开关设备类*/
struct _STR_XxxSwitchDevice{
	enum_XxxSwitchCheckStep step;						/**< 检测步骤 */
	unsigned char trigger;								/**< 有效触发条件 */
	enum_XxxSwitchDeviceType type;						/**< 类型 */
	
	unsigned short triggerCount;						/**< 触发计数器 */
	unsigned short upCount;								/**< 抬起计数器 */
	unsigned short triggerWaitVal;						/**< 触发消抖计数值 */
	unsigned short upWaitVal;							/**< 抬起消抖计数值 */
	unsigned short longVal;								/**< 长按计数值 */
	unsigned short continueVal;							/**< 持续长按间隔计数值 */
	#if CFG_XXXSWITCH_COMBOHIT
	unsigned short comboHitInterval;					/**< 连击间最大间隔 */
	unsigned short comboHitNum;							/**< 连击次数 */
	#endif

	unsigned char (*readInputStateFunc)(void);			/**< 读取输入状态函数函数指针 */
	void (*handleFunc)(enum_XxxSwitchCheckState state);	/**< 处理函数函数指针 */
	STR_XxxSwitchDevice* pNext;							/**< 指向下一个设备 */
};



static STR_XxxSwitchDevice* s_pKeyList = NULL;			/**< 开关设备链表入口(仅入口，最终直接指向设备实体，所需无需申请空间。链表是单向线性链表) */
/*检测*/
static void XxxSwitchDevice_Check(STR_XxxSwitchDevice* pKey);



/**
* @brief		获取开关设备类的大小(用于申请内存)
* @param		null
* @return		开关设备类的大小
* @par			注意事项：
* - null
* @par			示例:
* @code
*
* STR_XxxSwitchDevice* m_pKey;
* m_pKey = (STR_XxxSwitchDevice*)malloc(XxxSwitchDevice_GetSize());
*
* @endcode
*/
unsigned char XxxSwitchDevice_GetSize(void)
{
	return sizeof(STR_XxxSwitchDevice);
}



/**
* @brief		注册(自定义)
* @param[in]	pKey				设备对象指针
* @param[in]	type				设备类型
* @param[in]	trigger				有效状态
* @param[in]	triggerWaitVal		按下消抖tick次数，允许为零即不按下消抖
* @param[in]	upWaitVal			抬起消抖tick次数，允许为零即不抬起消抖
* @param[in]	longVal				长按响应tick次数，允许为零即关闭长按/长按抬起/持续长按事件
* @param[in]	continueVal			持续长按响应tick次数，允许为零即关闭持续长按事件
* @param[in]	comboHitInterval	连击响应允许的间隔tick次数，允许为零即关闭连击事件
* @param[in]	readInputStateFunc	读取设备状态的函数的函数指针
* @param[in]	handleFunc			应用层的事件处理函数的函数指针
* @return		注册是否成功
* - 0	注册成功
* - 1	配置完成，但设备已存在，无需加入链表
* - -1	pKey为空指针，无效设备
* @par			注意事项：
* - 当longVal设置为零时，关闭长按/长按抬起事件响应，同时伴随关闭持续长按事件响应，即导致continueVal设置值无效；
* @par			示例:
* @code
*
* XxxSwitchDevice_Register(m_pKey_1, SwitchDeviceType_Common, 1,	\
* 								2, 2,	\
* 								25, 25,	\
* 								0,	\
* 								ReadKEY1,	\
* 								(void (*)(enum_XxxSwitchCheckState state))Key1Handle);
*
* @endcode
*/
int XxxSwitchDevice_Register(STR_XxxSwitchDevice* pKey, enum_XxxSwitchDeviceType type, unsigned char trigger,	\
								unsigned short triggerWaitVal, unsigned short upWaitVal,	\
								unsigned short longVal, unsigned short continueVal,	\
								unsigned short comboHitInterval,    \
								unsigned char (*readInputStateFunc)(void),  \
								void (*handleFunc)(enum_XxxSwitchCheckState state)  \
								)
{
	if(NULL == pKey)return -1;							/* 返回错误：无效设备 */

	/*初始化*/
	pKey->step = SwitchCheckStep_Wait2Trigger;			/* 默认步骤为等待触发 */
	if(0 == trigger)									/* 防止调用者乱填，保证trigger只能0/1 */
	{
		pKey->trigger = 0;
	}
	else
	{
		pKey->trigger = 1;
	}
	pKey->type = type;
	pKey->triggerCount = 0;								/* 默认触发计数器清零 */
	pKey->upCount = 0;									/* 默认抬起计数器清零 */
	pKey->triggerWaitVal = triggerWaitVal;
	pKey->upWaitVal = upWaitVal;
	pKey->longVal = longVal;
	if(0 == pKey->longVal)								/* 如果长按功能关闭 */
	{
		pKey->continueVal = 0;							/* 伴随持续长按也关闭 */
	}
	else
	{
		pKey->continueVal = continueVal;
	}
	#if CFG_XXXSWITCH_COMBOHIT
	pKey->comboHitInterval = comboHitInterval;
	pKey->comboHitNum = 0;								/* 默认连击次数清零 */
	#endif
	#if CFG_XXXSWITCH_EDGETRIGGER
	if(SwitchDeviceType_EdgeTrigger == type)
	{
		pKey->upCount = pKey->upWaitVal;				/* 抬起计数器赋值抬起消抖计数 */
		pKey->step = SwitchCheckStep_WaitNotTrigge;		/* 如果是边沿触发类型默认步骤为等待复位 */
	}
	#endif
	pKey->readInputStateFunc = readInputStateFunc;
	pKey->handleFunc = handleFunc;

	/*遍历链表，防止添加重复*/
	for(STR_XxxSwitchDevice* pTemp = s_pKeyList; pTemp != NULL; pTemp = pTemp->pNext)
	{
		if(pTemp == pKey)
		{
			return 1;									/* 返回成功：配置完成，但设备已存在，无需加入链表 */
		}
	}
	/*加入链表*/
	pKey->pNext = s_pKeyList;
	s_pKeyList = pKey;									/* 把设备加入到链表头部 */

	return 0;											/* 返回成功：注册成功 */
}



/**
* @brief		配置长按事件(若关闭，则伴随关闭持续长按与长按抬起事件)
* @param[in]	pKey			设备对象指针
* @param[in]	longVal			长按响应tick次数，允许为零即关闭长按/长按抬起/持续长按事件
* @return		配置是否成功
* - 0	配置成功
* - -1	pKey为空指针，无效设备
* @par			注意事项：
* - null
* @par			示例:
* @code
*
* XxxSwitchDevice_CfgEvent_Long(m_pKey_1, 0);	//关闭长按/长按抬起/持续长按事件的响应
* XxxSwitchDevice_CfgEvent_Long(m_pKey_1, 25);	//开启长按/长按抬起事件的响应，如果continueVal有效则也开启持续长按事件的响应
*
* @endcode
*/
int XxxSwitchDevice_CfgEvent_Long(STR_XxxSwitchDevice* pKey, unsigned short longVal)
{
	if(NULL == pKey)return -1;							/* 返回错误：无效设备 */

	pKey->longVal = longVal;							/* 零值为关闭，非零为开启 */
	return 0;											/* 返回成功：配置成功 */
}
/**
* @brief		配置持续长按事件
* @param[in]	pKey			设备对象指针
* @param[in]	continueVal		持续长按响应tick次数，允许为零即关闭持续长按事件
* @return		配置是否成功
* - 0	配置成功
* - -1	pKey为空指针，无效设备
* @par			注意事项：
* - null
* @par			示例:
* @code
*
* XxxSwitchDevice_CfgEvent_Continue(m_pKey_1, 0);	//关闭持续长按事件的响应
* XxxSwitchDevice_CfgEvent_Continue(m_pKey_1, 25);	//开启持续长按事件的响应
*
* @endcode
*/
int XxxSwitchDevice_CfgEvent_Continue(STR_XxxSwitchDevice* pKey, unsigned short continueVal)
{
	if(NULL == pKey)return -1;							/* 返回错误：无效设备 */

	pKey->continueVal = continueVal;					/* 零值为关闭，非零为开启 */
	return 0;											/* 返回成功：配置成功 */
}
#if CFG_XXXSWITCH_COMBOHIT
/**
* @brief		配置连击事件
* @param[in]	pKey				设备对象指针
* @param[in]	comboHitInterval	连击允许间隔tick次数，允许为零即关闭连击事件
* @return		配置是否成功
* - 0	配置成功
* - -1	pKey为空指针，无效设备
* @par			注意事项：
* - null
* @par			示例:
* @code
*
* XxxSwitchDevice_CfgEvent_ComboHit(m_pKey_1, 0);	//关闭连击事件的响应
* XxxSwitchDevice_CfgEvent_ComboHit(m_pKey_1, 25);	//开启连击事件的响应
*
* @endcode
*/
int XxxSwitchDevice_CfgEvent_ComboHit(STR_XxxSwitchDevice* pKey, unsigned short comboHitInterval)
{
	if(NULL == pKey)return -1;							/* 返回错误：无效设备 */

	pKey->comboHitInterval = comboHitInterval;			/* 零值为关闭，非零为开启 */
	return 0;											/* 返回成功：配置成功 */
}
#endif



/**
* @brief		注销(由调用者自己回收内存)
* @param[in]	pKey			设备对象指针
* @return		注销是否成功
* - 0	注销成功
* - -1	pKey为空指针，无效设备
* - -2	链表为空
* - -3	查无该设备(设备未注册)
* @par			注意事项：
* - null
*/
int XxxSwitchDevice_Delete(STR_XxxSwitchDevice* pKey)
{
	if(NULL == pKey)return -1;							/* 返回错误：无效设备 */
	if(NULL == s_pKeyList)return -2;					/* 返回错误：链表为空 */

	if(s_pKeyList == pKey)								/* 如果pKey是位于链表头的设备 */
	{
		s_pKeyList = pKey->pNext;						/* 链表入口指向下个设备 */
		pKey->pNext = NULL;								/* 防止被删除的设备还能入侵链表 */
		return 0;										/* 返回成功：注销成功 */
	}

	/*遍历链表，找到对应开关设备并删除*/
	for(STR_XxxSwitchDevice* pTemp = s_pKeyList; pTemp->pNext != NULL; pTemp = pTemp->pNext)
	{
		if(pTemp->pNext == pKey)						/* 找到设备 */
		{
			pTemp->pNext = pTemp->pNext->pNext;			/* 链表间的链接越过设备，即删除 */
			pKey->pNext = NULL;							/* 防止被删除的设备还能入侵链表 */
			return 0;									/* 返回成功：注销成功 */
		}
	}

	return -3;											/* 返回错误：查无该设备(设备未注册) */
}



/**
* @brief		扫描
* @param		null
* @return		null
* @par			注意事项：
* - 注意外部tick基准是多少；
*/
void XxxSwitchDevice_Scan(void)
{
	/*遍历链表，扫描执行所有开关设备的检测*/
	for(STR_XxxSwitchDevice* pTemp = s_pKeyList; pTemp != NULL; pTemp = pTemp->pNext)
	{
		XxxSwitchDevice_Check(pTemp);
	}
}



/**
* @brief		是否触发
* @param[in]	pKey			设备对象指针
* @return		设备当前是否在被触发的状态(如按键当前是否被按住)
* - 0	非触发状态(如按键当前没被按住)
* - 1	触发状态(如按键当前被按住)
* @par			介绍：
* - 属于高级应用，用于开关设备间的联动。如：当一个按键的某事件触发时，需要先判断另一个按键是否触发，再判断自己是否执行某事件
*/
unsigned char XxxSwitchDevice_IsTrigger(STR_XxxSwitchDevice* pKey)
{
	if(pKey->step > SwitchCheckStep_Wait)				/* 根据枚举的值大小，大于即为触发 */
	{
		return 1;										/* 处于触发状态(按键按下/限位触发/传感器生效等) */
	}
	return 0;											/* 非触发状态 */
}



/**
* @brief		复位
* @param[in]	pKey			设备对象指针
* @return		null
* @par			介绍：
* - 属于高级应用，用于开关设备间的互斥。如：当按键按下，在抬起前被"复位"则会无法触发后续的事件(短按抬起/长按/持续长按/长按抬起/连击等)。
*/
void XxxSwitchDevice_Reset(STR_XxxSwitchDevice* pKey)
{
	#if CFG_XXXSWITCH_EDGETRIGGER
	if(SwitchDeviceType_EdgeTrigger == type)			/* 边沿触发类型 */
	{
		pKey->upCount = pKey->upWaitVal;				/* 抬起计数器赋值抬起消抖计数 */
		pKey->step = SwitchCheckStep_WaitNotTrigge;		/* 状态切换：等待复位 */
		return;
	}
	#endif

	pKey->step = SwitchCheckStep_Wait2Trigger;			/* 状态切换：等待触发 */
}



#if CFG_XXXSWITCH_COMBOHIT
/**
* @brief		读取连击次数
* @param[in]	pKey			设备对象指针
* @return		当前连击次数
* @par			注意事项：
* - 首次连击事件即为双击事件；
* - 仅在连击生效期间有效，连击被断则清零。即应在连击事件触发应用层事件处理函数时及时使用或另外保存；
*/
unsigned short XxxSwitchDevice_ReadComboHitNum(STR_XxxSwitchDevice* pKey)
{
	if(pKey->comboHitNum < 2)return 0;

	return pKey->comboHitNum;
}
#endif



/**
* @brief		检测
* @param[in]	pKey			设备对象指针
* @return		null
* @par			介绍：
* - 设备判断自身状态的核心代码，有兴趣的小伙伴可以看看。
* - 原本逻辑挺简单的，但加入支持无消抖/事件响应可开关/连击/边沿触发/等特性后就变复杂了。有能力的小伙伴可自行慎重裁剪
*/
static void XxxSwitchDevice_Check(STR_XxxSwitchDevice* pKey)
{
	switch(pKey->step)
	{
		case SwitchCheckStep_Wait2Trigger:/*等待触发*/
			if(pKey->readInputStateFunc() == pKey->trigger)					/* 设备触发条件满足 */
			{
				if(0 == pKey->triggerWaitVal)								/* 无需消抖 */
				{
					#if CFG_XXXSWITCH_EDGETRIGGER
					if(SwitchDeviceType_EdgeTrigger == pKey->type)			/* 边沿触发类型 */
					{
						pKey->upCount = pKey->upWaitVal;					/* 抬起计数器赋值抬起消抖计数 */
						pKey->step = SwitchCheckStep_WaitNotTrigge;			/* 状态切换：等待复位 */
						pKey->handleFunc(SwitchCheckState_EdgeTrigger);		/* 执行函数(边沿触发) */
						break;
					}
					#endif
					if(0 == pKey->longVal)									/* 长按计数为0，即关闭长按检测功能(伴随关闭持续长按与长按抬起功能) */
					{
						pKey->upCount = pKey->upWaitVal;					/* 抬起计数器赋值抬起消抖计数 */
						pKey->step = SwitchCheckStep_Wait2Up;				/* 状态切换：等待抬起 */
					}
					else													/* 开启长按检测功能 */
					{
						pKey->triggerCount = pKey->longVal;					/* 触发计数器赋值长按计数 */
						pKey->upCount = pKey->upWaitVal;					/* 抬起计数器赋值抬起消抖计数 */
						pKey->step = SwitchCheckStep_Wait2Long;				/* 状态切换：等待长按 */
					}
					pKey->handleFunc(SwitchCheckState_Click);				/* 执行函数(短按) */
				}
				else														/* 需要消抖 */
				{
					pKey->triggerCount = pKey->triggerWaitVal;				/* 触发计数器赋值触发消抖计数 */
					pKey->step = SwitchCheckStep_Wait;						/* 状态切换：消抖 */
				}
			}
			break;

		case SwitchCheckStep_Wait:/*消抖*/
			--pKey->triggerCount;
			if(0 == pKey->triggerCount)										/* 消抖完毕 */
			{
				if(pKey->readInputStateFunc() == pKey->trigger)				/* 设备触发条件满足 */
				{
					#if CFG_XXXSWITCH_EDGETRIGGER
					if(SwitchDeviceType_EdgeTrigger == pKey->type)			/* 边沿触发类型 */
					{
						pKey->upCount = pKey->upWaitVal;					/* 抬起计数器赋值抬起消抖计数 */
						pKey->step = SwitchCheckStep_WaitNotTrigge;			/* 状态切换：等待复位 */
						pKey->handleFunc(SwitchCheckState_EdgeTrigger);		/* 执行函数(边沿触发) */
						break;
					}
					#endif
					if(0 == pKey->longVal)									/* 长按计数为0，即关闭长按检测功能(伴随关闭持续长按与长按抬起功能) */
					{
						pKey->upCount = pKey->upWaitVal;					/* 抬起计数器赋值抬起消抖计数 */
						#if CFG_XXXSWITCH_COMBOHIT
						pKey->triggerCount = pKey->comboHitInterval;		/* 这里利用触发计数器来当连击间隔计时 */
						#endif
						pKey->step = SwitchCheckStep_Wait2Up;				/* 状态切换：等待抬起 */
					}
					else													/* 开启长按检测功能 */
					{
						pKey->triggerCount = pKey->longVal;					/* 触发计数器赋值长按计数 */
						pKey->upCount = pKey->upWaitVal;					/* 抬起计数器赋值抬起消抖计数 */
						pKey->step = SwitchCheckStep_Wait2Long;				/* 状态切换：等待长按 */
					}
					pKey->handleFunc(SwitchCheckState_Click);				/* 执行函数(短按) */
				}
				else														/* 设备触发条件不满足 判定为抖动/干扰 */
				{
					pKey->step = SwitchCheckStep_Wait2Trigger;				/* 状态切换：等待触发 */
				}
			}
			break;
			
		case SwitchCheckStep_Wait2Long:/*等待长按 */
			if(pKey->readInputStateFunc() == pKey->trigger)					/* 设备触发条件满足 */
			{
				pKey->upCount = pKey->upWaitVal;							/* 复位抬起计数器的抬起消抖计数(既然判定为按下了就提高抗失效能力) */
				--pKey->triggerCount;
				if(0 == pKey->triggerCount)									/* 满足长按时长 */
				{
					if(0 == pKey->continueVal)								/* 持续长按计数为0，即关闭持续长按功能 */
					{
						pKey->upCount = pKey->upWaitVal;					/* 抬起计数器赋值抬起消抖计数 */
						pKey->step = SwitchCheckStep_Wait2Up;				/* 状态切换：等待抬起 */
					}
					else
					{
						pKey->triggerCount = pKey->continueVal;				/* 触发计数器赋值持续长按计数 */
						pKey->upCount = pKey->upWaitVal;					/* 抬起计数器赋值抬起消抖计数 */
						pKey->step = SwitchCheckStep_Wait2Continue;			/* 状态切换：等待持续长按 */
					}
					pKey->handleFunc(SwitchCheckState_Long);				/* 执行函数(长按) */
				}
			}
			else															/* 设备触发条件失效 */
			{
				if(0 != pKey->upCount)										
				{
					--pKey->upCount;
				}
				else														/* 抬起消抖完毕 */
				{
					#if CFG_XXXSWITCH_COMBOHIT
					if(SwitchDeviceType_ComboHit == pKey->type)				/* 附带连击类型 */
					{
						if(0 != pKey->comboHitInterval)						/* 开启连击功能 */
						{
							pKey->comboHitNum = 1;							/* 连击数置一准备 */
							pKey->upCount = pKey->comboHitInterval;			/* 抬起计数器赋值连击最大间隔 */
							pKey->step = SwitchCheckStep_Wait2ComboHit;		/* 状态切换：等待连击 */
							pKey->handleFunc(SwitchCheckState_Click2Up);	/* 执行函数(短按抬起) */
							break;
						}
					}
					#endif
					pKey->step = SwitchCheckStep_Wait2Trigger;				/* 状态切换：等待触发 */
					pKey->handleFunc(SwitchCheckState_Click2Up);			/* 执行函数(短按抬起) */
				}
			}
			break;
			
		case SwitchCheckStep_Wait2Continue:/*等待持续长按*/
			if(pKey->readInputStateFunc() == pKey->trigger)					/* 设备触发条件满足 */
			{
				pKey->upCount = pKey->upWaitVal;							/* 复位抬起计数器的抬起消抖计数(既然判定为按下了就提高抗失效能力) */
				--pKey->triggerCount;
				if(0 == pKey->triggerCount)									/* 满足持续长按时长 */
				{
					pKey->triggerCount = pKey->continueVal;					/* 复位触发计数器的持续长按计数 */
					pKey->handleFunc(SwitchCheckState_Continue);			/* 执行函数(持续长按) */
				}
			}
			else															/* 设备触发条件失效 */
			{
				if(0 != pKey->upCount)
				{
					--pKey->upCount;
				}
				else														/* 抬起消抖完毕 */
				{
					pKey->step = SwitchCheckStep_Wait2Trigger;				/* 状态切换：等待触发 */
					pKey->handleFunc(SwitchCheckState_Long2Up);				/* 执行函数(长按抬起) */
				}
			}
			break;
			
		case SwitchCheckStep_Wait2Up:/*等待抬起 */
			if(pKey->readInputStateFunc() != pKey->trigger)					/* 设备触发条件失效 */
			{
				if(0 != pKey->upCount)
				{
					--pKey->upCount;
				}
				else														/* 抬起消抖完毕 */
				{
					if(0 == pKey->longVal)									/* 关闭长按功能 */
					{
						#if CFG_XXXSWITCH_COMBOHIT
						if(SwitchDeviceType_ComboHit == pKey->type)			/* 附带连击类型 */
						{
							if(0 != pKey->comboHitInterval)					/* 开启连击功能 */
							{
								if(0 != pKey->triggerCount)					/* 连击间隔未超时，则准备连击判断 */
								{
									pKey->comboHitNum = 1;						/* 连击数置一准备 */
									pKey->upCount = pKey->comboHitInterval;		/* 抬起计数器赋值连击最大间隔 */
									pKey->step = SwitchCheckStep_Wait2ComboHit;	/* 状态切换：等待连击 */
								}
								else											/* 连击间隔超时，则恢复正常等待 */
								{
									pKey->step = SwitchCheckStep_Wait2Trigger;	/* 状态切换：等待触发 */
								}
								pKey->handleFunc(SwitchCheckState_Click2Up);/* 执行函数(短按抬起) */
								break;
							}
						}
						#endif
						pKey->step = SwitchCheckStep_Wait2Trigger;			/* 状态切换：等待触发 */
						pKey->handleFunc(SwitchCheckState_Click2Up);		/* 执行函数(短按抬起) */
					}
					else													/* 长按功能有效 */
					{
						pKey->step = SwitchCheckStep_Wait2Trigger;			/* 状态切换：等待触发 */
						pKey->handleFunc(SwitchCheckState_Long2Up);			/* 执行函数(长按抬起) */
					}
				}
				break;
			}
			pKey->upCount = pKey->upWaitVal;								/* 设备触发条件仍然有效，则复位抬起计数器的抬起消抖计数 */

			#if CFG_XXXSWITCH_COMBOHIT
			if(0 != pKey->triggerCount)										/* 这里利用触发计数器来当连击间隔计数 */
			{
				--pKey->triggerCount;
			}
			#endif
			break;
			
		#if CFG_XXXSWITCH_COMBOHIT
		case SwitchCheckStep_Wait2ComboHit:/*等待连击*/
			if(pKey->readInputStateFunc() == pKey->trigger)					/* 在连击间隔内设备触发条件有效 */
			{
				if(0 == pKey->triggerWaitVal)								/* 无需消抖 */
				{
					pKey->upCount = pKey->comboHitInterval;					/* 复位抬起计数器的连击最大间隔 */
					pKey->triggerCount = pKey->upWaitVal;					/* 由于抬起计数器要用作于连击间隔计时，所以使用触发计数器来做抬起消抖 */
					++pKey->comboHitNum;
					pKey->step = SwitchCheckStep_Wait2ComboHitUp;			/* 状态切换：等待连击抬起 */
					pKey->handleFunc(SwitchCheckState_ComboHit);			/* 执行函数(连击) */
				}
				else														/* 需要消抖 */
				{
					pKey->triggerCount = pKey->triggerWaitVal;				/* 触发计数器赋值触发消抖计数 */
					pKey->step = SwitchCheckStep_ComboHitWait;				/* 状态切换：连击消抖 */
				}
				break;
			}
			if(0 != pKey->upCount)
			{
				--pKey->upCount;
			}
			else															/* 在连击间隔时间内没有触发则连击断掉，恢复正常等待 */
			{
				pKey->comboHitNum = 0;										/* 清零连击数 */
				pKey->step = SwitchCheckStep_Wait2Trigger;					/* 状态切换：等待触发 */
			}
			break;

		case SwitchCheckStep_ComboHitWait:/*连击消抖*/
			--pKey->triggerCount;
			if(0 == pKey->triggerCount)										/* 消抖完毕 */
			{
				if(pKey->readInputStateFunc() == pKey->trigger)				/* 设备触发条件有效 */
				{
					pKey->upCount = pKey->comboHitInterval;					/* 复位抬起计数器的连击最大间隔 */
					pKey->triggerCount = pKey->upWaitVal;					/* 由于抬起计数器要用作于连击间隔计时，所以使用触发计数器来做抬起消抖 */
					++pKey->comboHitNum;
					pKey->step = SwitchCheckStep_Wait2ComboHitUp;			/* 状态切换：等待连击抬起 */
					pKey->handleFunc(SwitchCheckState_ComboHit);			/* 执行函数(连击) */
				}
				else
				{
					pKey->step = SwitchCheckStep_Wait2ComboHit;				/* 状态切换：等待连击 */
				}
				break;
			}
			if(0 != pKey->upCount)
			{
				--pKey->upCount;
			}
			else															/* 在连击间隔时间内没有任何操作则连击断掉，恢复正常等待 */
			{
				pKey->comboHitNum = 0;										/* 清零连击数 */
				pKey->step = SwitchCheckStep_Wait2Trigger;					/* 状态切换：等待触发 */
			}
			break;

		case SwitchCheckStep_Wait2ComboHitUp:/*等待连击抬起*/
			if(pKey->readInputStateFunc() != pKey->trigger)					/* 设备触发条件失效 */
			{
				if(0 != pKey->triggerCount)									/* 由触发计数器来做抬起消抖 */
				{
					--pKey->triggerCount;
				}
				else
				{
					pKey->upCount = pKey->comboHitInterval;					/* 复位抬起计数器的连击最大间隔，等待下次连击 */
					pKey->step = SwitchCheckStep_Wait2ComboHit;				/* 状态切换：等待连击 */
				}
				break;
			}
			if(0 != pKey->upCount)
			{
				--pKey->upCount;
			}
			else															/* 在连击间隔时间内没有任何操作则连击断掉，等待复位 */
			{
				pKey->upCount = pKey->upWaitVal;							/* 抬起计数器赋值抬起消抖计数 */
				pKey->comboHitNum = 0;										/* 清零连击数 */
				pKey->step = SwitchCheckStep_WaitNotTrigge;					/* 状态切换：等待复位 */
			}
			break;
		#endif

		#if (CFG_XXXSWITCH_COMBOHIT || CFG_XXXSWITCH_EDGETRIGGER)
		case SwitchCheckStep_WaitNotTrigge:/*等待复位*/
			if(pKey->readInputStateFunc() != pKey->trigger)					/* 设备触发条件失效 */
			{
				if(0 != pKey->upCount)
				{
					--pKey->upCount;
				}
				else														/* 抬起消抖完毕 */
				{
					pKey->step = SwitchCheckStep_Wait2Trigger;				/* 状态切换：等待触发 */
				}
				break;
			}
			pKey->upCount = pKey->upWaitVal;								/* 设备触发条件仍然有效，则复位抬起计数器的抬起消抖计数 */
			break;
		#endif
	}
}
